home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
program
/
svgakt50.zip
/
SRC
/
SVGAKIT
/
SVGA.ASM
< prev
next >
Wrap
Assembly Source File
|
1994-08-23
|
63KB
|
2,206 lines
;****************************************************************************
;*
;* The SuperVGA Kit
;*
;* Copyright (C) 1994 SciTech Software
;* All rights reserved.
;*
;* Filename: $RCSfile: svga.asm $
;* Version: $Revision: 1.1 $
;*
;* Language: 80386 Assembler
;* Environment: IBM PC Real Mode and 16/32 bit Protected Mode.
;*
;* Description: Assembly language support routines for the SuperVGA test
;* library. All the code here assumes that the video memory
;* selector has been cached in the FS selector before the
;* code is called.
;*
;* $Id: svga.asm 1.1 1994/08/22 12:27:00 kjb release $
;*
;****************************************************************************
IDEAL
INCLUDE "model.mac" ; Memory model macros
header svga ; Set up memory model
CRTC EQU 3D4h ; Port of CRTC registers
$EXTRN _maxx,UINT
$EXTRN _maxy,UINT
$EXTRN _maxcolor,ULONG
$EXTRN _maxpage,UINT
$EXTRN _bytesperline,USHORT
$EXTRN _pagesize,ULONG
$EXTRN _curBank,UINT
$EXTRN _bankSwitch,ULONG
$EXTRN _bankShift,UINT
$EXTRN _writeBank,ULONG ; Relocated write bank routine
$EXTRN _readBank,ULONG ; Relocated read bank routine
$EXTRN _extendedflipping,BOOL
begdataseg svga
originOffset DW ? ; Offset of current page in buffer
bankOffset DW ? ; Bank offset in total video memory
enddataseg svga
begcodeseg svga
;----------------------------------------------------------------------------
; int _setFS(unsigned sel)
;----------------------------------------------------------------------------
; Set the FS register to the specified selector value. This register is
; never changed, so we only ever need to do it once (to save time with
; expensive selector loads in protected mode).
;----------------------------------------------------------------------------
procstart __setFS
ARG sel:UINT
push _bp
mov _bp,_sp
mov _ax,[sel]
mov cx,fs
mov fs,ax
mov ax,cx
pop _bp
ret
procend __setFS
;----------------------------------------------------------------------------
; PixelAddr16 Determine buffer address of pixel in SVGA 16 color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: AH - bit mask
; _BX - byte offset in buffer
; CL - number of bits to shift left
; _SI - 64k bank number of the address
; FS - video buffer segment
;
; Registers: none.
;
;----------------------------------------------------------------------------
PROC PixelAddr16 near
push _dx ; Save DX
mul [_bytesperline] ; DX:AX := y * BytesPerLine
mov cl,bl ; CL := low-order byte of x
shr _bx,3 ; _BX := x/8
add bx,ax
adc dl,0 ; DL:_BX := y*BytesPerLine + x/8
add bx,[originOffset] ; _BX := byte offset in video buffer
adc dl,[BYTE bankOffset]; DL := bank number
mov _si,_dx ; _SI := bank number
mov ah,1 ; AH := unshifted bit mask
and cl,7 ; CL := x & 7
xor cl,7 ; CL := # bits to shift left
pop _dx
ret
ENDP PixelAddr16
;----------------------------------------------------------------------------
; PixelAddr256 Determine buffer address of pixel in SVGA 256 color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: _BX - byte offset in buffer
; _DX - 64k bank number of the address
; FS - video buffer segment
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr256 near
mul [_bytesperline] ; DX:AX := y * bytesperline
add bx,ax
adc dx,0 ; DX:_BX := y * BytesPerLine + x
add bx,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
ret
ENDP PixelAddr256
;----------------------------------------------------------------------------
; PixelAddr32k Determine buffer address of pixel in SVGA 32k color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: _BX - byte offset in buffer
; _DX - 64k bank number of the address
; FS - video buffer segment
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr32k near
mul [_bytesperline] ; DX:AX := y * bytesperline
shl _bx,1
add bx,ax
adc dx,0 ; DX:BX := y * BytesPerLine + x * 2
add bx,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
ret
ENDP PixelAddr32k
;----------------------------------------------------------------------------
; PixelAddr16m Determine buffer address of pixel in SVGA 16m color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: _BX - byte offset in buffer
; _DX - 64k bank number of the address
; FS - video buffer segment
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr16m near
mul [_bytesperline] ; DX:AX := y * bytesperline
add ax,bx
shl _bx,1
add bx,ax
adc dx,0 ; DX:BX := y * BytesPerLine + x * 3
add bx,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
ret
ENDP PixelAddr16m
;----------------------------------------------------------------------------
; PixelAddr4G Determine buffer address of pixel in SVGA 32k color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: _BX - byte offset in buffer
; _DX - 64k bank number of the address
; FS - video buffer segment
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr4G near
mul [_bytesperline] ; DX:AX := y * bytesperline
shl _bx,2
add bx,ax
adc dx,0 ; DX:BX := y * BytesPerLine + x * 2
add bx,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
ret
ENDP PixelAddr4G
;----------------------------------------------------------------------------
; void clear16(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Works even if the display contains more than
; one bank, so will work for 1024x768 and 1280x1024 video modes.
;----------------------------------------------------------------------------
procstart __clear16
ARG color:ULONG
enter_c 0
push es
; Setup graphics controller
mov dx,3CEh ; DX := Graphics Controller I/O port
mov ah,[BYTE color] ; AH := Background color
xor al,al ; AL := 0 (Set/Reset register number)
out dx,ax ; load set/reset register
mov ax,0F01h ; AH := 1111b (mask for Enable set/reset)
; AL := 1 (enable Set/reset reg number)
out dx,ax ; load enable set/reset reg
mov _ax,[_maxy]
inc _ax
mul [_bytesperline] ; DX:AX := number of bytes to fill
mov bx,ax ; BX := bytes in last bank to fill
mov dh,dl ; DH := number of full banks to fill
mov ax,fs
mov es,ax
xor _di,_di ; ES:_DI -> video memory
add di,[originOffset]
mov ax,[bankOffset] ; AX := starting bank number
cld ; Moves go up in memory
or dh,dh ; More than one bank to fill?
jz @@SingleBank ; No, only fill a single bank
; Fill all of the full 64k banks first
@@OuterLoop:
call setBank
mov _cx,4000h ; Need to set 4000h double USHORTs per bank
rep stosd
xor _di,_di
inc al
dec dh
jnz @@OuterLoop
; Now fill the last partial bank
@@SingleBank:
call setBank
xor _cx,_cx
mov cx,bx
shr _cx,2 ; _CX := number of double USHORTs to set
rep stosd
; Restore graphics controller
mov dx,3CEh ; DX := Graphics Controller I/O port
xor ax,ax ; AH := 0, AL := 0
out dx,ax ; Restore default Set/Reset register
inc ax ; AH := 0, AL := 1
out dx,ax ; Restore enable Set/Reset register
pop es
leave_c
ret
procend __clear16
;----------------------------------------------------------------------------
; void clear256(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart __clear256
ARG color:ULONG
enter_c 0
push es
xor eax,eax
mov al,[BYTE color]
mov ebx,eax
shl ebx,8
or eax,ebx
mov ebx,eax
shl ebx,16
or eax,ebx
mov [color],eax ; Color = 32 bit color value
mov _ax,[_maxy]
inc _ax
mul [_bytesperline] ; DX:AX := number of bytes to fill
mov bx,ax ; BX := bytes in last bank to fill
mov dh,dl ; DH := number of full banks to fill
mov ax,fs
mov es,ax
xor _di,_di ; ES:_DI -> start of video memory
add di,[originOffset]
mov dl,[BYTE bankOffset]; DL := starting bank number
cld ; Moves go up in memory
or dh,dh ; More than one bank to fill?
jz @@SingleBank ; No, only fill a single bank
; Fill all of the full 64k banks first
@@OuterLoop:
mov al,dl
call setBank
mov eax,[color]
mov _cx,4000h ; Need to set 4000h double USHORTs per bank
rep stosd
xor _di,_di
inc dl
dec dh
jnz @@OuterLoop
; Now fill the last partial bank
@@SingleBank:
mov al,dl
call setBank
mov eax,[color]
xor _cx,_cx
mov cx,bx
shr _cx,2 ; _CX := number of double USHORTs to set
rep stosd
pop es
leave_c
ret
procend __clear256
;----------------------------------------------------------------------------
; void clear32k(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart __clear32k
ARG color:ULONG
enter_c 0
push es
xor eax,eax
mov ax,[WORD color]
mov ebx,eax
shl ebx,16
or eax,ebx
mov [color],eax ; Color = 32 bit color value
mov _ax,[_maxy]
inc _ax
mul [_bytesperline] ; DX:AX := number of bytes to fill
mov bx,ax ; BX := bytes in last bank to fill
mov dh,dl ; DH := number of full banks to fill
mov ax,fs
mov es,ax
xor _di,_di ; ES:_DI -> start of video memory
add di,[originOffset]
mov dl,[BYTE bankOffset]; DL := starting bank number
cld ; Moves go up in memory
; Fill all of the full 64k banks first
@@OuterLoop:
mov al,dl
call setBank
mov eax,[color]
mov _cx,4000h ; Need to set 4000h double USHORTs per bank
rep stosd
xor _di,_di
inc dl
dec dh
jnz @@OuterLoop
; Now fill the last partial bank
mov al,dl
call setBank
mov eax,[color]
xor _cx,_cx
mov cx,bx
shr _cx,2 ; _CX := number of double USHORTs to set
rep stosd
pop es
leave_c
ret
procend __clear32k
;----------------------------------------------------------------------------
; void clear16m(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart __clear16m
ARG color:ULONG
enter_c 0
push _bp
xor _bx,_bx ; FS:_BX -> start of video memory
add bx,[originOffset]
mov dl,[BYTE bankOffset]; DL := starting bank number
mov ax,dx
call setBank ; Change to starting bank number
mov _di,[_maxx]
inc _di ; _DI := number of pixels to draw
mov _si,[_maxy]
inc _si ; _SI := number of lines to process
mov ax,[WORD color] ; AX := pixel color
mov dh,[BYTE color+2] ; DH := top byte of pixel color
mov bp,di
shl bp,1
add bp,di ; BP := bytes per physical scanline
sub bp,[_bytesperline]
neg bp ; BP := scanline adjust factor
@@NextScanLine:
mov _cx,_di
@@LoopSolid:
cmp bx,0FFFDh
jae @@BankSwitch ; Bank switch occurs!
mov [WORD fs:_bx],ax ; Set pixel value in buffer
mov [BYTE fs:_bx+2],dh
add _bx,3 ; Increment to next pixel
loop @@LoopSolid ; Loop across line
@@AfterPlot:
add bx,bp
jc @@BankSwitch2
dec _si
jnz @@NextScanLine
jmp @@Exit
@@BankSwitch:
call DrawPixelSlow16m
inc dl
loop @@LoopSolid ; Loop across line
jmp @@AfterPlot
@@BankSwitch2:
inc dl
push _ax
mov _ax,_dx
call setBank
pop _ax
dec _si
jnz @@NextScanLine
@@Exit:
pop _bp
leave_c
ret
procend __clear16m
;----------------------------------------------------------------------------
; void clear4G(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart __clear4G
ARG color:ULONG
enter_c 0
push es
mov _ax,[_maxy]
inc _ax
mul [_bytesperline] ; DX:AX := number of bytes to fill
mov bx,ax ; BX := bytes in last bank to fill
mov dh,dl ; DH := number of full banks to fill
mov ax,fs
mov es,ax
xor _di,_di ; ES:_DI -> start of video memory
add di,[originOffset]
mov dl,[BYTE bankOffset]; DL := starting bank number
cld ; Moves go up in memory
; Fill all of the full 64k banks first
@@OuterLoop:
mov al,dl
call setBank
mov eax,[color]
mov _cx,4000h ; Need to set 4000h double USHORTs per bank
rep stosd
xor _di,_di
inc dl
dec dh
jnz @@OuterLoop
; Now fill the last partial bank
mov al,dl
call setBank
mov eax,[color]
xor _cx,_cx
mov cx,bx
shr _cx,2 ; _CX := number of double USHORTs to set
rep stosd
pop es
leave_c
ret
procend __clear4G
;----------------------------------------------------------------------------
; void putPixel16(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart __putPixel16
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
; Compute the pixel's address in video buffer
mov _ax,[y]
mov _bx,[x]
mul [_bytesperline] ; DX:AX := y * BytesPerLine
mov cl,bl ; CL := low-order byte of x
shr _bx,3 ; _BX := x/8
add bx,ax
adc dx,0 ; DX:BX := y*BytesPerLine + x/8
add bx,[originOffset] ; DX:BX := byte offset in video buffer
adc dx,[bankOffset]
cmp dl,[BYTE _curBank]
je @@NoChange
mov al,dl
call setBank
@@NoChange:
mov ah,1 ; AH := unshifted bit mask
and cl,7 ; CL := x & 7
xor cl,7 ; CL := # bits to shift left
; set Graphics Controller Bit Mask register
shl ah,cl ; AH := bit mask in proper postion
mov dx,3CEh ; GC address register port
mov al,8 ; AL := Bit Mask Register number
out dx,ax
; set Graphics Controller Mode register
mov ax,0205h ; AL := Mode register number
; AH := Write mode 2 (bits 0,1)
; Read mode 0 (bit 3)
out dx,ax
; set data rotate/Function Select register
mov ax,3 ; AL := Data Rotate/Func select reg #
out dx,ax
; set the pixel value
mov al,[fs:_bx] ; latch one byte from each bit plane
mov al,[BYTE color] ; AL := pixel value
mov [fs:_bx],al ; update all bit planes
; restore default Graphics Controller registers
mov ax,0FF08h ; default bit mask
out dx,ax
mov ax,0005 ; default mode register
out dx,ax
mov ax,0003 ; default function select
out dx,ax
leave_c
ret
procend __putPixel16
;----------------------------------------------------------------------------
; void putPixel256(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart __putPixel256
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
mov _ax,[y]
mul [_bytesperline]
mov _bx,[x]
add ax,bx
adc dx,0 ; DX:AX := y * BytesPerLine + x
add ax,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
mov bx,ax ; BX := Offset in buffer
cmp dl,[BYTE _curBank]
je @@NoChange
mov al,dl
call setBank
@@NoChange:
mov al,[BYTE color]
mov [fs:_bx],al ; Replace the pixel
leave_c
ret
procend __putPixel256
;----------------------------------------------------------------------------
; void putPixel32k(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart __putPixel32k
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
mov _ax,[y]
mul [_bytesperline]
mov _bx,[x]
shl _bx,1
add ax,bx
adc dx,0 ; DX:AX := y * BytesPerLine + x * 2
add ax,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
mov bx,ax ; BX := Offset in buffer
cmp dl,[BYTE _curBank]
je @@NoChange
mov al,dl
call setBank
@@NoChange:
mov ax,[USHORT color]
mov [fs:_bx],ax ; Replace the pixel
leave_c
ret
procend __putPixel32k
;----------------------------------------------------------------------------
; void putPixel16m(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart __putPixel16m
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
mov _ax,[y]
mul [_bytesperline]
mov _bx,[x]
add ax,bx
adc dx,0
shl bx,1
add ax,bx
adc dx,0 ; DX:AX := y * BytesPerLine + x * 3
add ax,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
mov bx,ax ; BX := Offset in buffer
cmp dl,[BYTE _curBank]
je @@NoChange
mov al,dl
call setBank
@@NoChange:
mov ax,[WORD color]
mov dh,[BYTE color+2]
cmp bx,0FFFEh
jae @@SlowVersion ; Bank switch occurs in pixel!
mov [fs:_bx],ax ; Replace the first byte
mov [fs:_bx+2],dh
@@Exit: leave_c
ret
@@SlowVersion:
call DrawPixelSlow16m ; Draw the pixel slowly
jmp @@Exit
procend __putPixel16m
;----------------------------------------------------------------------------
; IncBXDL Increment the BX/DL offset bank number combination
;----------------------------------------------------------------------------
;
; This routine is called in place to increment the value of DL:BX where
; DL is the current bank offset, and BX is the current frame buffer offset.
; The routine also ensures that the bank boundary is correctly crossed. It
; is slow, but only gets called for about less than 10 pixels on the entire
; display page.
;
; Entry: BX - Video buffer offset
; DL - Video bank number
;
; Exit: BX - New buffer offset (+1)
; DL - New bank bumber (carried over from BX)
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC IncBXDL near
add bx,1
adc dl,0
xchg al,dl
call setBank
xchg al,dl
ret
ENDP IncBXDL
;----------------------------------------------------------------------------
; DrawPixelSlow16m Draws a pixel split across a bank boundary correctly
;----------------------------------------------------------------------------
;
; Draws the pixel taking into account that a bank boundary occurs in the
; middle of the pixel.
;
; Entry: DH:AX - Color of the pixel to plot
; FS:_BX - Address of pixel to plot
; _curBank - Current bank number
;
; Exit: DH:AX - Color of pixel to plot
; FS:_BX - Address of pixel to plot + 3
; _curBank - Current bank number + 1
;
; Registers: All preserved.
;
;----------------------------------------------------------------------------
PROC DrawPixelSlow16m near
push _dx
mov dl,[BYTE _curBank]
mov [fs:_bx],al ; Replace the pixel
call IncBXDL
mov [fs:_bx],ah
call IncBXDL
mov [fs:_bx],dh
call IncBXDL
pop _dx
ret
ENDP DrawPixelSlow16m
;----------------------------------------------------------------------------
; void putPixel4G(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart __putPixel4G
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
mov _ax,[y]
mul [_bytesperline]
mov _bx,[x]
shl _bx,1
shl _bx,1
add ax,bx
adc dx,0 ; DX:AX := y * BytesPerLine + x * 4
add ax,[originOffset]
adc dl,[BYTE bankOffset]; DL := bank number
mov bx,ax ; BX := Offset in buffer
cmp dl,[BYTE _curBank]
je @@NoChange
mov al,dl
call setBank
@@NoChange:
mov eax,[color]
mov [fs:_BX],eax ; Replace the pixel
leave_c
ret
procend __putPixel4G
;----------------------------------------------------------------------------
; void _line16(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart __line16
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL Routine:NCPTR, VertInc:ULONG, EIncr:UINT, \
NEIncr:UINT = LocalSize
enter_c LocalSize
cld
; Configure the graphics controller (write mode 3)
mov dx,3CEh ; DX := Graphics Controller port addr
mov ax,0B05h ; AL := Mode register number
; AH := Write mode 3 (bits 0,1)
; Read mode 1 (bit 3)
out dx,ax
xor ah,ah ; AH := replace mode
mov al,3 ; AL := Data Rotate/Func select reg #
out dx,ax
mov ax,0007h ; AH := 0 (don't care for all maps;
; CPU reads always return 0FFH)
; AL := 7 (Color Don't care reg number)
out dx,ax ; Set up Color Don't care reg
mov ax,0F01h ; AH := 1111b (bit plane mask for
; enable Set/Reset)
out dx,ax ; AL := Enable Set/Reset Register #
mov ax,0FF08h ; AH := 11111111b, AL := 8
out dx,ax ; restore bit mask register
; Load the current color
mov dx,3CEh ; DX := Graphics Controller port addr
mov ah,[BYTE color] ; Get color value into ah
xor al,al ; AL := Set/Reset Register number
out dx,ax
mov si,[_bytesperline] ; Increment for video buffer
mov [USHORT VertInc+2],0 ; Zero out sign for vertical increment
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg si ; negative increment for buffer
mov [USHORT VertInc+2],0FFFFh ; ensure vert increment is negative
; select appropriate routine for slope of line
@@Y2Greater:
mov [USHORT VertInc],si ; save increment
mov [Routine],offset @@LoSlopeLine
cmp _bx,_ax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [Routine],offset @@HiSlopeLine
xchg _bx,_ax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl _bx,1 ; _BX := 2 * dy
mov [EIncr],_bx ; EIncr := 2 * dy
sub _bx,_ax ; d = 2 * dy - dx
mov _di,_bx ; DI := initial decision variable
sub _bx,_ax
mov [NEIncr],_bx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push _ax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr16 ; AH := Bit mask
; FS:_BX -> buffer
; CL := # bits to shift left
; _SI := bank number
shl ah,cl ; AH := bit mask in proper position
mov al,ah ; AL := bit Mask
pop _cx ; Restore dx
inc _cx ; _CX := # pixels to draw
jmp [Routine] ; jump to appropriate routine
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; FS:_BX -> video buffer
; AL = bit mask for 1st pixel
; AH = bit mask for 1st pixel
; _CX = # pixels to draw
; DX = Graphics Controller data register port addr
; _SI = bank number
; _DI = Initial decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
; The Graphics Controller index register should be set to point to the
; Bit Mask register.
;
;****************************************************************************
@@LoSlopeLine:
@@StartLo:
mov al,ah ; AL := bit mask for next pixel
cmp si,[USHORT _curBank]
je @@BitMaskIn
push _ax ; Preserve AX
mov _ax,_si ; AX := new bank number
call setBank ; Program this bank
pop _ax
@@BitMaskIn:
or al,ah ; mask current pixel position
ror ah,1 ; Rotate pixel value
jc @@BitMaskOut ; Jump if mask rotated to leftmost pixel
; bit mask not shifted out
or _di,_di ; test sign of d
jns @@InPosDi ; jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@BitMaskIn
and [fs:_bx],al ; set remaining pixel(s)
jmp @@Exit
@@InPosDi:
add _di,[NEIncr] ; d := d + NEIncr
and [fs:_bx],al ; Update bit planes
add bx,[USHORT VertInc] ; increment y
adc si,[USHORT VertInc+2] ; Adjust bank number
loop @@StartLo
jmp @@Exit
; bit mask shifted out
@@BitMaskOut:
and [fs:_bx],al ; Update bit planes
add bx,1 ; increment x
adc si,0 ; Adjust bank value
or _di,_di ; test sign of d
jns @@OutPosDi ; jump if non-negative
add _di,[EIncr] ; d := d + EIncr
loop @@StartLo
jmp @@Exit
@@OutPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,[USHORT VertInc] ; vertical increment
adc si,[USHORT VertInc+2] ; Adjust bank number
loop @@StartLo
jmp @@Exit
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; FS:_BX -> video buffer
; AL = bit mask for 1st pixel
; _CX = # pixels to draw
; DX = Graphics Controller data register port addr
; _SI = bank number
; _DI = Initial decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
; The Graphics Controller index register should be set to point to the
; Bit Mask register.
;
;****************************************************************************
@@HiSlopeLine:
@@StartHi:
cmp si,[USHORT _curBank]
je @@SetHi
push _ax ; Preserve AX
mov _ax,_si ; AX := new bank number
call setBank ; Program this bank
pop _ax
@@SetHi:
and [fs:_bx],al ; update bit planes
add bx,[USHORT VertInc] ; increment y
adc si,[USHORT VertInc+2] ; Adjust bank number
or _di,_di ; test sign of d
jns @@HiPosDi ; jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@StartHi
jmp @@Exit
@@HiPosDi:
add _di,[NEIncr] ; d := d + NEIncr
ror al,1 ; rotate bit mask
adc bx,0 ; Increment BX when mask rotated to
; leftmost pixel position
adc si,0 ; Adjust bank number
loop @@StartHi
; Restore graphics controller and return to caller
@@Exit:
mov dx,3CEh ; DX := Graphics Controller port addr
xor ax,ax ; AH := 0, AL := 0
out dx,ax ; Restore Set/Reset Register
inc ax ; AH := 0, AL := 1
out dx,ax ; Restore Enable Set/Reset register
mov al,3 ; AH := 0, AL := 3
out dx,ax ; Restore Data Rotate/Func select reg
mov al,5 ; AH := 0, AL := 5
out dx,ax ; default mode register
mov ax,0F07h ; default color compare value
out dx,ax
mov ax,0FF08h ; AH := 11111111b, AL := 8
out dx,ax ; restore bit mask register
leave_c
ret
procend __line16
;----------------------------------------------------------------------------
; void _line256(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart __line256
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL Routine:NCPTR, VertInc:ULONG, EIncr:UINT, \
NEIncr:UINT = LocalSize
enter_c LocalSize
mov si,[_bytesperline] ; Increment for video buffer
mov [USHORT VertInc+2],0 ; Zero out sign for vertical increment
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg si ; negative increment for buffer
mov [USHORT VertInc+2],0FFFFh ; ensure vert increment is negative
; select appropriate routine for slope of line
@@Y2Greater:
mov [USHORT VertInc],si ; save increment
mov [Routine],offset @@LoSlopeLine
cmp _bx,_ax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [Routine],offset @@HiSlopeLine
xchg _bx,_ax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl _bx,1 ; _BX := 2 * dy
mov [EIncr],_bx ; EIncr := 2 * dy
sub _bx,_ax ; d = 2 * dy - dx
mov _di,_bx ; _DI := initial decision variable
sub _bx,_ax
mov [NEIncr],_bx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push _ax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr256 ; FS:_BX -> buffer
pop _cx ; Restore dx
inc _cx ; CX := # pixels to draw
jmp [Routine] ; jump to appropriate routine
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; FS:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov al,0
call setBank
mov al,[BYTE color] ; AL := pixel value to fill
mov dh,[BYTE _curBank] ; DH := current bank number
@@LoopLo:
cmp dl,dh
je @@SetLo
mov dh,al ; DH := color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
mov al,dh ; AL := color value
mov dh,dl ; DH := current bank number
@@SetLo:
mov [fs:_bx],al ; Set pixel value in buffer
add bx,1 ; Increment x coordinate
adc dl,0 ; Adjust bank number
or _di,_di ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; adjust page number
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; ES:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov al,[BYTE color] ; AL := pixel value to fill
mov dh,[BYTE _curBank] ; DH := current bank number
@@LoopHi:
cmp dh,dl
je @@SetHi
mov dh,al ; DH := color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
mov al,dh ; AL := color value
mov dh,dl ; DH := current bank number
@@SetHi:
mov [fs:_bx],al ; Set pixel value in buffer
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; Adjust bank number
or _di,_di ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,1 ; Increment x
adc dl,0 ; Adjust bank number
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
leave_c
ret
procend __line256
;----------------------------------------------------------------------------
; void _line32k(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart __line32k
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL Routine:NCPTR, VertInc:ULONG, EIncr:UINT, \
NEIncr:UINT = LocalSize
enter_c LocalSize
cld
mov si,[_bytesperline] ; Increment for video buffer
mov [USHORT VertInc+2],0 ; Zero out sign for vertical increment
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg si ; negative increment for buffer
mov [USHORT VertInc+2],0FFFFh ; ensure vert increment is negative
; select appropriate routine for slope of line
@@Y2Greater:
mov [USHORT VertInc],si ; save increment
mov [Routine],offset @@LoSlopeLine
cmp _bx,_ax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [Routine],offset @@HiSlopeLine
xchg _bx,_ax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl _bx,1 ; _BX := 2 * dy
mov [EIncr],_bx ; EIncr := 2 * dy
sub _bx,_ax ; d = 2 * dy - dx
mov _di,_bx ; _DI := initial decision variable
sub _bx,_ax
mov [NEIncr],_bx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push _ax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr32k ; FS:_BX -> buffer
pop _cx ; Restore dx
inc _cx ; _CX := # pixels to draw
jmp [Routine] ; jump to appropriate routine
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; FS:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov ax,[USHORT color] ; AX := pixel value to fill
mov dh,[BYTE _curBank] ; DH := current bank number
@@LoopLo:
cmp dl,dh
je @@SetLo
push _ax ; Save color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
mov dh,dl ; DH := current bank number
pop _ax ; Restore color value
@@SetLo:
mov [fs:_bx],ax ; Set pixel value in buffer
add bx,2 ; Increment x coordinate
adc dl,0 ; Adjust bank number
or _di,_di ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; adjust page number
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; FS:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov ax,[USHORT color] ; AL := pixel value to fill
mov dh,[BYTE _curBank] ; DH := current bank number
@@LoopHi:
cmp dh,dl
je @@SetHi
push _ax ; Save color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
mov dh,dl ; DH := current bank number
pop _ax ; Restore color value
@@SetHi:
mov [fs:_bx],ax ; Set pixel value in buffer
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; Adjust bank number
or _di,_di ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,2 ; Increment x
adc dl,0 ; Adjust bank number
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
leave_c
ret
procend __line32k
;----------------------------------------------------------------------------
; void _line16m(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart __line16m
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL Routine:NCPTR, VertInc:ULONG, EIncr:UINT, \
NEIncr:UINT = LocalSize
enter_c LocalSize
cld
mov si,[_bytesperline] ; Increment for video buffer
mov [USHORT VertInc+2],0 ; Zero out sign for vertical increment
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg si ; negative increment for buffer
mov [USHORT VertInc+2],0FFFFh ; ensure vert increment is negative
; select appropriate routine for slope of line
@@Y2Greater:
mov [USHORT VertInc],si ; save increment
mov [Routine],offset @@LoSlopeLine
cmp _bx,_ax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [Routine],offset @@HiSlopeLine
xchg _bx,_ax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl _bx,1 ; _BX := 2 * dy
mov [EIncr],_bx ; EIncr := 2 * dy
sub _bx,_ax ; d = 2 * dy - dx
mov _di,_bx ; _DI := initial decision variable
sub _bx,_ax
mov [NEIncr],_bx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push _ax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr16m ; FS:_BX -> buffer
pop _cx ; Restore dx
inc _cx ; CX := # pixels to draw
jmp [Routine] ; jump to appropriate routine
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; FS:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov ax,[USHORT color] ; AX := pixel value to fill
mov dh,[BYTE color+2] ; DH := top byte of pixel value
@@LoopLo:
cmp dl,[BYTE _curBank]
je @@SetPixelLo
push _ax ; Save color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
pop _ax ; Restore color value
@@SetPixelLo:
cmp bx,0FFFEh
jae @@BankSwitchLo
@@SetLo:
mov [fs:_bx],ax ; Set pixel value in buffer
mov [fs:_bx+2],dh
add bx,3 ; Increment x coordinate
adc dl,0 ; Adjust bank number
@@DonePixelLo:
or _di,_di ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; adjust page number
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@BankSwitchLo:
call DrawPixelSlow16m
inc dl
jmp @@DonePixelLo
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; FS:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov ax,[USHORT color] ; AL := pixel value to fill
mov dh,[BYTE color+2] ; DH := current bank number
@@LoopHi:
cmp dl,[BYTE _curBank]
je @@SetPixelHi
push _ax ; Save color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
pop _ax ; Restore color value
@@SetPixelHi:
cmp bx,0FFFEh
jae @@BankSwitchHi
@@SetHi:
mov [fs:_bx],ax ; Set pixel value in buffer
mov [fs:_bx+2],dh
@@DonePixelHi:
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; Adjust bank number
or _di,_di ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,3 ; Increment x
adc dl,0 ; Adjust bank number
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit
@@BankSwitchHi:
call DrawPixelSlow16m
sub bx,3
jmp @@DonePixelHi
@@Exit:
leave_c
ret
procend __line16m
;----------------------------------------------------------------------------
; void _line4G(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart __line4G
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL Routine:NCPTR, VertInc:ULONG, EIncr:UINT, \
NEIncr:UINT = LocalSize
enter_c LocalSize
push eax
cld
mov si,[_bytesperline] ; Increment for video buffer
mov [USHORT VertInc+2],0 ; Zero out sign for vertical increment
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg si ; negative increment for buffer
mov [USHORT VertInc+2],0FFFFh ; ensure vert increment is negative
; select appropriate routine for slope of line
@@Y2Greater:
mov [USHORT VertInc],si ; save increment
mov [Routine],offset @@LoSlopeLine
cmp _bx,_ax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [Routine],offset @@HiSlopeLine
xchg _bx,_ax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl _bx,1 ; _BX := 2 * dy
mov [EIncr],_bx ; EIncr := 2 * dy
sub _bx,_ax ; d = 2 * dy - dx
mov _di,_bx ; _DI := initial decision variable
sub _bx,_ax
mov [NEIncr],_bx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push _ax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr4G ; FS:_BX -> buffer
pop _cx ; Restore dx
inc _cx ; _CX := # pixels to draw
jmp [Routine] ; jump to appropriate routine
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; ES:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov eax,[color] ; EAX := pixel value to fill
mov dh,[BYTE _curBank] ; DH := current bank number
@@LoopLo:
cmp dl,dh
je @@SetLo
push _ax ; Save color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
mov dh,dl ; DH := current bank number
pop _ax ; Restore color value
@@SetLo:
mov [fs:_bx],eax ; Set pixel value in buffer
add bx,4 ; Increment x coordinate
adc dl,0 ; Adjust bank number
or _di,_di ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; adjust page number
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; ES:_BX -> video buffer
; _CX = # pixels to draw
; _DX = Bank number for first pixel
; _DI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov eax,[color] ; EAX := pixel value to fill
mov dh,[BYTE _curBank] ; DH := current bank number
@@LoopHi:
cmp dh,dl
je @@SetHi
push _ax ; Save color value
mov al,dl ; AL := new bank number
call setBank ; Program this bank
mov dh,dl ; DH := current bank number
pop _ax ; Restore color value
@@SetHi:
mov [fs:_bx],eax ; Set pixel value in buffer
add bx,[USHORT VertInc] ; increment y
adc dl,[BYTE VertInc+2] ; Adjust bank number
or _di,_di ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add _di,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add _di,[NEIncr] ; d := d + NEIncr
add bx,4 ; Increment x
adc dl,0 ; Adjust bank number
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
pop eax
leave_c
ret
procend __line4G
;----------------------------------------------------------------------------
; void setActivePage(int which)
;----------------------------------------------------------------------------
; Routine to set the video page for active output.
;
; Entry: page - Page number of page to use
;
;----------------------------------------------------------------------------
procstart _setActivePage
ARG which:UINT
enter_c 0
; Calculate 18 bit address of page in video memory
xor eax,eax
mov _ax,[which] ; EAX := page number
mul [_pagesize] ; EDX:EAX := result
mov [originOffset],ax ; Save video buffer offset
shr eax,16
mov [bankOffset],ax ; Save video bank offset
leave_c
ret
procend _setActivePage
;----------------------------------------------------------------------------
; void setVisualPage(int which)
;----------------------------------------------------------------------------
; Routine to set the visible video page.
;
; Entry: page - Page number of page to use
;
;----------------------------------------------------------------------------
procstart _setVisualPage
ARG which:UINT
enter_c 0
cmp [_maxpage],0 ; No flipping if only one page
je @@Exit
; Calculate 18 bit address of page in video memory
xor eax,eax
mov _ax,[which] ; EAX := page number
mul [_pagesize] ; EAX := starting address in memory
mov edx,eax
shr edx,16 ; DX:AX := starting address in memory
cmp [_extendedflipping],0
je @@VGAFlip ; We have no extended page flipping
div [_bytesperline] ; AX := starting scanline,
; DX := starting byte
mov cx,dx
cmp [USHORT _maxcolor],0Fh
je @@16Color
cmp [USHORT _maxcolor],0FFh
je @@SetIt
cmp [USHORT _maxcolor+2],0FFh
je @@16MColor
shr cx,1 ; CX := starting pixel in buffer
jmp @@SetIt
@@16Color:
shl cx,3 ; CX := starting pixel in buffer
jmp @@SetIt
@@16MColor:
mov bx,ax ; Preserve AX
xor dx,dx
mov ax,cx
mov cx,3
div cx
mov cx,ax ; CX := starting pixel in buffer
mov ax,bx ; Restore AX
@@SetIt:
mov bx,ax ; BX := starting scanline in buffer
mov _ax,04F07h
mov _dx,_bx ; DX := starting scanline number
xor _bx,_bx ; BX := 0 - set display start
int 10h ; Set the display start address
jmp @@Exit
@@VGAFlip:
mov bx,ax ; BX := bottom 16 bits of address
; Wait for display enable to be active (active low), to be sure that
; both halves of the start address will take place in one frame. We
; preload a few values here to save time after the DE has been
; detected.
mov cl,0Ch ; CL := Start Address High register
mov ch,bh ; CH := high byte of new address
mov bh,bl ; BH := low byte of new address
mov bl,0Dh ; BL := Start Address Low register
mov dx,03DAh ; DX := video status port
@@WaitDEVGA:
in al,dx
test al,1
jnz @@WaitDEVGA ; Wait for Display Enable
cli
mov dx,03D4h ; DX := CRTC I/O port (3D4h)
mov ax,bx
out dx,ax
mov ax,cx
out dx,ax
sti
; Now wait for the start of the vertical sync, to ensure that the old
; page will be invisible before anything is drawn on it.
mov dx,03DAh ; DX := video status port
@@WaitStartVert:
in al,dx ; Wait for start of vertical retrace
test al,8
jz @@WaitStartVert
@@Exit:
leave_c
ret
procend _setVisualPage
;----------------------------------------------------------------------------
; setBank Sets the read/write bank from assembly language
;----------------------------------------------------------------------------
;
; Entry: AL - New read/write bank number
;
; Exit: AL - New read/write bank number
;
; Registers: All preserved!
;
; Note that some VESA BIOSes and TSR's set the first window to be
; write only and the second window to be read only, so we need to set both
; windows for most common operations to the same value. The Universal
; VESA VBE sets both the read and write banks to the same value for
; Window A, and changed the read bank only for Window B, hence the second
; call is _not_ required when the Universal VESA VBE is installed. You can
; determine what the window does by looking at the WindowAAttributes in
; the SuperVGAInfo block returned by function 00h. You could use this
; information to optimise bank switching when using faster VBE's like
; the Universal VESA VBE (but I have no bothered to do that here).
;----------------------------------------------------------------------------
procstart setBank
push _dx
ife flatmodel
push ds
mov dx,DGROUP ; Address our data segment
mov ds,dx
endif
mov [_curBank],_ax ; Save current write bank number
cmp [_writeBank],0
je @@VESABank
mov _dx,_ax ; DX := bank number
call [_writeBank] ; Call relocated version
ife flatmodel
pop ds
endif
pop _dx
ret
@@VESABank:
push _ax
push _bx
push _cx
mov cl,[BYTE _bankShift]; Adjust to VESA granularity
shl al,cl
push _ax
mov _dx,_ax ; DX := bank number
xor _bx,_bx ; BX := select window A
cmp [_bankSwitch],0
je @@UseInt10
call [_bankSwitch] ; Set write window
pop _dx
inc _bx
call [_bankSwitch] ; Set read window
jmp @@Exit
; Use the int 10h interface if the bankSwitch routine is NULL, which will
; be the case in protected mode until VBE 2.0 (unless UniVBE 5.0 or above
; is installed).
@@UseInt10:
mov _ax,04F05h
int 10h
pop _dx
inc _bx
mov _ax,04F05h
int 10h
@@Exit: pop _cx
pop _bx
pop _ax
ife flatmodel
pop ds
endif
pop _dx
ret
procend setBank
;----------------------------------------------------------------------------
; setReadBank Sets the read bank from assembly language
;----------------------------------------------------------------------------
;
; Entry: AL - New read bank number
;
; Exit: AL - New read bank number
;
; Registers: All preserved!
;
;----------------------------------------------------------------------------
procstart setReadBank
push _dx
ife flatmodel
push ds
mov dx,DGROUP ; Address our data segment
mov ds,dx
endif
mov [_curBank],-1 ; Ensure banking will be re-loaded
cmp [_readBank],0
je @@VESABank
mov _dx,_ax ; DX := bank number
call [_readBank] ; Call relocated version
ife flatmodel
pop ds
endif
pop _dx
ret
@@VESABank:
push _ax
push _bx
push _cx
mov cl,[BYTE _bankShift]; Adjust to VESA granularity
shl al,cl
mov _dx,_ax ; DX := bank number
mov _bx,1 ; BX := select window B
cmp [_bankSwitch],0
je @@UseInt10
call [_bankSwitch] ; Set read window
jmp @@Exit
; Use the int 10h interface if the bankSwitch routine is NULL, which will
; be the case in protected mode until VBE 2.0 (unless UniVBE 4.4 or above
; is installed).
@@UseInt10:
mov _ax,04F05h
int 10h
@@Exit: pop _cx
pop _bx
pop _ax
ife flatmodel
pop ds
endif
pop _dx
ret
procend setReadBank
;----------------------------------------------------------------------------
; void setBank(int bank)
;----------------------------------------------------------------------------
; Sets the new read/write bank number from C
;----------------------------------------------------------------------------
procstart _setBank
ARG bank:UINT
push _bp
mov _bp,_sp
mov _ax,[bank]
call setBank
pop _bp
ret
procend _setBank
;----------------------------------------------------------------------------
; void setReadBank(int bank)
;----------------------------------------------------------------------------
; Sets the new reading bank number from C
;----------------------------------------------------------------------------
procstart _setReadBank
ARG bank:UINT
push _bp
mov _bp,_sp
mov _ax,[bank]
call setReadBank
pop _bp
ret
procend _setReadBank
endcodeseg svga
END